package demoMod.anm2editor.ui;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import demoMod.anm2editor.interfaces.ReloadStringsSubscriber;
import demoMod.anm2editor.localization.LocalizedStrings;
import demoMod.anm2editor.model.*;
import demoMod.anm2editor.utils.Preferences;
import demoMod.gdxform.core.FormManager;
import demoMod.gdxform.enums.GFrameCloseStrategy;
import demoMod.gdxform.enums.GFrameWindowStyle;
import demoMod.gdxform.ui.*;

import java.util.ArrayList;
import java.util.List;

public class KeyFramePropertyPanel extends GFrame implements ReloadStringsSubscriber {
    public static final String ID = "KeyFramePropertyPanel";
    private final HistoryPanel historyPanel;

    public KeyFramePropertyPanel(BitmapFont bannerFont) {
        super(2, Gdx.graphics.getHeight() * 0.2F + 23, Gdx.graphics.getWidth() * 0.15F, Gdx.graphics.getHeight() * 0.6F - 45, bannerFont, GFrameWindowStyle.CLOSE_BUTTON_ONLY, false);
        List<String> strings = LocalizedStrings.getStrings(ID);
        setTitle(strings.get(0));
        setResizable(false);
        setCloseStrategy(GFrameCloseStrategy.HIDDEN_ON_CLOSE);
        setId(ID);
        LocalizedStrings.subscribe(this);
        historyPanel = (HistoryPanel) FormManager.getInstance().getContainerById(HistoryPanel.ID);
        GLabel lPosition = new GLabel(getWidth() * 0.05F, getHeight() * 0.88F + getHeight() * 0.035F, getWidth(), getHeight() * 0.07F, bannerFont);
        lPosition.setText(strings.get(1));
        lPosition.setId("lPosition");
        GLabel lOrigin = new GLabel(getWidth() * 0.05F, getHeight() * 0.8F + getHeight() * 0.035F, getWidth(), getHeight() * 0.07F, bannerFont);
        lOrigin.setText(strings.get(2));
        lOrigin.setId("lOrigin");
        GLabel lSrc = new GLabel(getWidth() * 0.05F, getHeight() * 0.72F + getHeight() * 0.035F, getWidth(), getHeight() * 0.07F, bannerFont);
        lSrc.setText(strings.get(3));
        lSrc.setId("lSrc");
        GLabel lSize = new GLabel(getWidth() * 0.05F, getHeight() * 0.64F + getHeight() * 0.035F, getWidth(), getHeight() * 0.07F, bannerFont);
        lSize.setText(strings.get(4));
        lSize.setId("lSize");
        GLabel lScale = new GLabel(getWidth() * 0.05F, getHeight() * 0.56F + getHeight() * 0.035F, getWidth(), getHeight() * 0.07F, bannerFont);
        lScale.setText(strings.get(5));
        lScale.setId("lScale");
        GLabel lDelay = new GLabel(getWidth() * 0.05F, getHeight() * 0.48F + getHeight() * 0.035F, getWidth(), getHeight() * 0.07F, bannerFont);
        lDelay.setText(strings.get(6));
        lDelay.setId("lDelay");
        GLabel lRotation = new GLabel(getWidth() * 0.05F, getHeight() * 0.4F + getHeight() * 0.035F, getWidth(), getHeight() * 0.07F, bannerFont);
        lRotation.setText(strings.get(7));
        lRotation.setId("lRotation");
        GLabel lVisible = new GLabel(getWidth() * 0.05F, getHeight() * 0.32F + getHeight() * 0.035F, getWidth(), getHeight() * 0.07F, bannerFont);
        lVisible.setText(strings.get(8));
        lVisible.setId("lVisible");
        GLabel lTint = new GLabel(getWidth() * 0.05F, getHeight() * 0.24F + getHeight() * 0.035F, getWidth(), getHeight() * 0.07F, bannerFont);
        lTint.setText(strings.get(9));
        lTint.setId("lTint");
        GLabel lColorOffset = new GLabel(getWidth() * 0.05F, getHeight() * 0.16F + getHeight() * 0.035F, getWidth(), getHeight() * 0.07F, bannerFont);
        lColorOffset.setText(strings.get(10));
        lColorOffset.setId("lColorOffset");
        GLabel lInter = new GLabel(getWidth() * 0.05F, getHeight() * 0.08F + getHeight() * 0.035F, getWidth(), getHeight() * 0.07F, bannerFont);
        lInter.setText(strings.get(11));
        lInter.setId("lInter");
        GLabel lAreaName = new GLabel(getWidth() * 0.05F, getHeight() * 0.035F, getWidth(), getHeight() * 0.07F, bannerFont);
        lAreaName.setText(strings.get(23));
        lAreaName.setId("lAreaName");
        lAreaName.setVisible(false);
        addElement(lPosition);
        addElement(lOrigin);
        addElement(lSrc);
        addElement(lSize);
        addElement(lScale);
        addElement(lDelay);
        addElement(lRotation);
        addElement(lVisible);
        addElement(lTint);
        addElement(lColorOffset);
        addElement(lInter);
        addElement(lAreaName);

        final Timeline timeline = (Timeline) FormManager.getInstance().getContainerById(Timeline.ID);
        GTextField x = new GTextField(getWidth() * 0.35F, lPosition.getY(false) - getHeight() * 0.035F, getWidth() * 0.2F, lPosition.getHeight(), bannerFont) {
            @Override
            public boolean keyDown(int keyCode) {
                if (keyCode == Input.Keys.ENTER && FormManager.getInstance().getEventHooks().getCurrentFocusedElement() == this) {
                    FormManager.getInstance().getEventHooks().setCurrentFocusedElement(getParent());
                    return true;
                }
                return super.keyDown(keyCode);
            }

            @Override
            public void deactivate() {
                super.deactivate();
                KeyFrame keyFrame = timeline.getCurrentSelectedKeyFrame();
                if (getText().length() > 0 && getText().length() < 10 && keyFrame != null) {
                    KeyFrame stateBeforeOperation = keyFrame.makeCopy();
                    keyFrame.xPosition = Float.parseFloat(getText());
                    KeyFrame stateAfterOperation = keyFrame.makeCopy();
                    if (keyFrame.xPosition != stateBeforeOperation.xPosition) {
                        Operation operation = getOperation(stateBeforeOperation, stateAfterOperation, keyFrame);
                        operation.setName(LocalizedStrings.getStrings(ID).get(12));
                        historyPanel.addOperation(operation);
                        refreshKeyFrameProperty();
                    }
                }
            }
        };
        x.setId("x");
        x.setCharFilter("[0-9.\\-]");
        GTextField y = new GTextField(getWidth() * 0.55F + 3, lPosition.getY(false) - getHeight() * 0.035F, getWidth() * 0.2F, lPosition.getHeight(), bannerFont) {
            @Override
            public boolean keyDown(int keyCode) {
                if (keyCode == Input.Keys.ENTER && FormManager.getInstance().getEventHooks().getCurrentFocusedElement() == this) {
                    FormManager.getInstance().getEventHooks().setCurrentFocusedElement(getParent());
                    return true;
                }
                return super.keyDown(keyCode);
            }

            @Override
            public void deactivate() {
                super.deactivate();
                KeyFrame keyFrame = timeline.getCurrentSelectedKeyFrame();
                if (getText().length() > 0 && getText().length() < 10 && keyFrame != null) {
                    KeyFrame stateBeforeOperation = keyFrame.makeCopy();
                    keyFrame.yPosition = Float.parseFloat(getText());
                    KeyFrame stateAfterOperation = keyFrame.makeCopy();
                    if (keyFrame.yPosition != stateBeforeOperation.yPosition) {
                        Operation operation = getOperation(stateBeforeOperation, stateAfterOperation, keyFrame);
                        operation.setName(LocalizedStrings.getStrings(ID).get(12));
                        historyPanel.addOperation(operation);
                        refreshKeyFrameProperty();
                    }
                }
            }
        };
        y.setId("y");
        y.setCharFilter("[0-9.\\-]");

        GTextField originX = new GTextField(getWidth() * 0.25F, lOrigin.getY(false) - getHeight() * 0.035F, getWidth() * 0.2F, lOrigin.getHeight(), bannerFont) {
            @Override
            public boolean keyDown(int keyCode) {
                if (keyCode == Input.Keys.ENTER && FormManager.getInstance().getEventHooks().getCurrentFocusedElement() == this) {
                    FormManager.getInstance().getEventHooks().setCurrentFocusedElement(getParent());
                    return true;
                }
                return super.keyDown(keyCode);
            }

            @Override
            public void deactivate() {
                super.deactivate();
                KeyFrame keyFrame = timeline.getCurrentSelectedKeyFrame();
                if (getText().length() > 0 && getText().length() < 10 && keyFrame != null) {
                    KeyFrame stateBeforeOperation = keyFrame.makeCopy();
                    keyFrame.xPivot = Float.parseFloat(getText());
                    KeyFrame stateAfterOperation = keyFrame.makeCopy();
                    if (keyFrame.xPivot != stateBeforeOperation.xPivot) {
                        Operation operation = getOperation(stateBeforeOperation, stateAfterOperation, keyFrame);
                        operation.setName(LocalizedStrings.getStrings(ID).get(13));
                        historyPanel.addOperation(operation);
                        refreshKeyFrameProperty();
                    }
                }
            }
        };
        originX.setId("originX");
        originX.setCharFilter("[0-9.\\-]");
        GTextField originY = new GTextField(getWidth() * 0.45F + 3, lOrigin.getY(false) - getHeight() * 0.035F, getWidth() * 0.2F, lOrigin.getHeight(), bannerFont) {
            @Override
            public boolean keyDown(int keyCode) {
                if (keyCode == Input.Keys.ENTER && FormManager.getInstance().getEventHooks().getCurrentFocusedElement() == this) {
                    FormManager.getInstance().getEventHooks().setCurrentFocusedElement(getParent());
                    return true;
                }
                return super.keyDown(keyCode);
            }

            @Override
            public void deactivate() {
                super.deactivate();
                KeyFrame keyFrame = timeline.getCurrentSelectedKeyFrame();
                if (getText().length() > 0 && getText().length() < 10 && keyFrame != null) {
                    KeyFrame stateBeforeOperation = keyFrame.makeCopy();
                    keyFrame.yPivot = Float.parseFloat(getText());
                    KeyFrame stateAfterOperation = keyFrame.makeCopy();
                    if (keyFrame.yPivot != stateBeforeOperation.yPivot) {
                        Operation operation = getOperation(stateBeforeOperation, stateAfterOperation, keyFrame);
                        operation.setName(LocalizedStrings.getStrings(ID).get(13));
                        historyPanel.addOperation(operation);
                        refreshKeyFrameProperty();
                    }
                }
            }
        };
        originY.setId("originY");
        originY.setCharFilter("[0-9.\\-]");

        GTextField srcX = new GTextField(getWidth() * 0.25F, lSrc.getY(false) - getHeight() * 0.035F, getWidth() * 0.2F, lSrc.getHeight(), bannerFont) {
            @Override
            public boolean keyDown(int keyCode) {
                if (keyCode == Input.Keys.ENTER && FormManager.getInstance().getEventHooks().getCurrentFocusedElement() == this) {
                    FormManager.getInstance().getEventHooks().setCurrentFocusedElement(getParent());
                    return true;
                }
                return super.keyDown(keyCode);
            }

            @Override
            public void deactivate() {
                super.deactivate();
                KeyFrame keyFrame = timeline.getCurrentSelectedKeyFrame();
                if (getText().length() > 0 && getText().length() < 10 && keyFrame != null) {
                    KeyFrame stateBeforeOperation = keyFrame.makeCopy();
                    keyFrame.xCrop = (int) Double.parseDouble(getText());
                    KeyFrame stateAfterOperation = keyFrame.makeCopy();
                    if (keyFrame.xCrop != stateBeforeOperation.xCrop) {
                        Operation operation = getOperation(stateBeforeOperation, stateAfterOperation, keyFrame);
                        operation.setName(LocalizedStrings.getStrings(ID).get(14));
                        historyPanel.addOperation(operation);
                        refreshKeyFrameProperty();
                    }
                }
            }
        };
        srcX.setId("srcX");
        srcX.setCharFilter("[0-9]");
        GTextField srcY = new GTextField(getWidth() * 0.45F + 3, lSrc.getY(false) - getHeight() * 0.035F, getWidth() * 0.2F, lSrc.getHeight(), bannerFont) {
            @Override
            public boolean keyDown(int keyCode) {
                if (keyCode == Input.Keys.ENTER && FormManager.getInstance().getEventHooks().getCurrentFocusedElement() == this) {
                    FormManager.getInstance().getEventHooks().setCurrentFocusedElement(getParent());
                    return true;
                }
                return super.keyDown(keyCode);
            }

            @Override
            public void deactivate() {
                super.deactivate();
                KeyFrame keyFrame = timeline.getCurrentSelectedKeyFrame();
                if (getText().length() > 0 && getText().length() < 10 && keyFrame != null) {
                    KeyFrame stateBeforeOperation = keyFrame.makeCopy();
                    keyFrame.yCrop = (int) Double.parseDouble(getText());
                    KeyFrame stateAfterOperation = keyFrame.makeCopy();
                    if (keyFrame.yCrop != stateBeforeOperation.yCrop) {
                        Operation operation = getOperation(stateBeforeOperation, stateAfterOperation, keyFrame);
                        operation.setName(LocalizedStrings.getStrings(ID).get(14));
                        historyPanel.addOperation(operation);
                        refreshKeyFrameProperty();
                    }
                }
            }
        };
        srcY.setId("srcY");
        srcY.setCharFilter("[0-9]");

        GTextField width = new GTextField(getWidth() * 0.25F, lSize.getY(false) - getHeight() * 0.035F, getWidth() * 0.2F, lSize.getHeight(), bannerFont) {
            @Override
            public boolean keyDown(int keyCode) {
                if (keyCode == Input.Keys.ENTER && FormManager.getInstance().getEventHooks().getCurrentFocusedElement() == this) {
                    FormManager.getInstance().getEventHooks().setCurrentFocusedElement(getParent());
                    return true;
                }
                return super.keyDown(keyCode);
            }

            @Override
            public void deactivate() {
                super.deactivate();
                KeyFrame keyFrame = timeline.getCurrentSelectedKeyFrame();
                if (getText().length() > 0 && getText().length() < 10 && keyFrame != null) {
                    KeyFrame stateBeforeOperation = keyFrame.makeCopy();
                    keyFrame.width = (int) Double.parseDouble(getText());
                    KeyFrame stateAfterOperation = keyFrame.makeCopy();
                    if (keyFrame.width != stateBeforeOperation.width) {
                        Operation operation = getOperation(stateBeforeOperation, stateAfterOperation, keyFrame);
                        operation.setName(LocalizedStrings.getStrings(ID).get(15));
                        historyPanel.addOperation(operation);
                        refreshKeyFrameProperty();
                    }
                }
            }
        };
        width.setId("width");
        width.setCharFilter("[0-9]");
        GTextField height = new GTextField(getWidth() * 0.45F + 3, lSize.getY(false) - getHeight() * 0.035F, getWidth() * 0.2F, lSize.getHeight(), bannerFont) {
            @Override
            public boolean keyDown(int keyCode) {
                if (keyCode == Input.Keys.ENTER && FormManager.getInstance().getEventHooks().getCurrentFocusedElement() == this) {
                    FormManager.getInstance().getEventHooks().setCurrentFocusedElement(getParent());
                    return true;
                }
                return super.keyDown(keyCode);
            }

            @Override
            public void deactivate() {
                super.deactivate();
                KeyFrame keyFrame = timeline.getCurrentSelectedKeyFrame();
                if (getText().length() > 0 && getText().length() < 10 && keyFrame != null) {
                    KeyFrame stateBeforeOperation = keyFrame.makeCopy();
                    keyFrame.height = (int) Double.parseDouble(getText());
                    KeyFrame stateAfterOperation = keyFrame.makeCopy();
                    if (keyFrame.height != stateBeforeOperation.height) {
                        Operation operation = getOperation(stateBeforeOperation, stateAfterOperation, keyFrame);
                        operation.setName(LocalizedStrings.getStrings(ID).get(15));
                        historyPanel.addOperation(operation);
                        refreshKeyFrameProperty();
                    }
                }
            }
        };
        height.setId("height");
        height.setCharFilter("[0-9]");

        GTextField scaleX = new GTextField(getWidth() * 0.25F, lScale.getY(false) - getHeight() * 0.035F, getWidth() * 0.2F, lScale.getHeight(), bannerFont) {
            @Override
            public boolean keyDown(int keyCode) {
                if (keyCode == Input.Keys.ENTER && FormManager.getInstance().getEventHooks().getCurrentFocusedElement() == this) {
                    FormManager.getInstance().getEventHooks().setCurrentFocusedElement(getParent());
                    return true;
                }
                return super.keyDown(keyCode);
            }

            @Override
            public void deactivate() {
                super.deactivate();
                KeyFrame keyFrame = timeline.getCurrentSelectedKeyFrame();
                if (getText().length() > 0 && getText().length() < 10 && keyFrame != null) {
                    KeyFrame stateBeforeOperation = keyFrame.makeCopy();
                    keyFrame.xScale = Float.parseFloat(getText());
                    KeyFrame stateAfterOperation = keyFrame.makeCopy();
                    if (keyFrame.xScale != stateBeforeOperation.xScale) {
                        Operation operation = getOperation(stateBeforeOperation, stateAfterOperation, keyFrame);
                        operation.setName(LocalizedStrings.getStrings(ID).get(16));
                        historyPanel.addOperation(operation);
                        refreshKeyFrameProperty();
                    }
                }
            }
        };
        scaleX.setId("scaleX");
        scaleX.setCharFilter("[0-9.\\-]");
        GTextField scaleY = new GTextField(getWidth() * 0.45F + 3, lScale.getY(false) - getHeight() * 0.035F, getWidth() * 0.2F, lScale.getHeight(), bannerFont) {
            @Override
            public boolean keyDown(int keyCode) {
                if (keyCode == Input.Keys.ENTER && FormManager.getInstance().getEventHooks().getCurrentFocusedElement() == this) {
                    FormManager.getInstance().getEventHooks().setCurrentFocusedElement(getParent());
                    return true;
                }
                return super.keyDown(keyCode);
            }

            @Override
            public void deactivate() {
                super.deactivate();
                KeyFrame keyFrame = timeline.getCurrentSelectedKeyFrame();
                if (getText().length() > 0 && getText().length() < 10 && keyFrame != null) {
                    KeyFrame stateBeforeOperation = keyFrame.makeCopy();
                    keyFrame.yScale = Float.parseFloat(getText());
                    KeyFrame stateAfterOperation = keyFrame.makeCopy();
                    if (keyFrame.yScale != stateBeforeOperation.yScale) {
                        Operation operation = getOperation(stateBeforeOperation, stateAfterOperation, keyFrame);
                        operation.setName(LocalizedStrings.getStrings(ID).get(16));
                        historyPanel.addOperation(operation);
                        refreshKeyFrameProperty();
                    }
                }
            }
        };
        scaleY.setId("scaleY");
        scaleY.setCharFilter("[0-9.\\-]");

        GTextField delay = new GTextField(getWidth() * 0.35F, lDelay.getY(false) - getHeight() * 0.035F, getWidth() * 0.2F, lDelay.getHeight(), bannerFont) {
            @Override
            public boolean keyDown(int keyCode) {
                if (keyCode == Input.Keys.ENTER && FormManager.getInstance().getEventHooks().getCurrentFocusedElement() == this) {
                    FormManager.getInstance().getEventHooks().setCurrentFocusedElement(getParent());
                    return true;
                }
                return super.keyDown(keyCode);
            }

            @Override
            public void deactivate() {
                super.deactivate();
                KeyFrame keyFrame = timeline.getCurrentSelectedKeyFrame();
                if (getText().length() > 0 && getText().length() < 10 && keyFrame != null) {
                    KeyFrame stateBeforeOperation = keyFrame.makeCopy();
                    keyFrame.delay = (int) Double.parseDouble(getText());
                    KeyFrame stateAfterOperation = keyFrame.makeCopy();
                    if (keyFrame.delay != stateBeforeOperation.delay) {
                        Operation operation = getOperation(stateBeforeOperation, stateAfterOperation, keyFrame);
                        operation.setName(LocalizedStrings.getStrings(ID).get(17));
                        historyPanel.addOperation(operation);
                        refreshKeyFrameProperty();
                    }
                }
            }
        };
        delay.setId("delay");
        delay.setCharFilter("[0-9]");

        GTextField rotation = new GTextField(getWidth() * 0.35F, lRotation.getY(false) - getHeight() * 0.035F, getWidth() * 0.2F, lDelay.getHeight(), bannerFont) {
            @Override
            public boolean keyDown(int keyCode) {
                if (keyCode == Input.Keys.ENTER && FormManager.getInstance().getEventHooks().getCurrentFocusedElement() == this) {
                    FormManager.getInstance().getEventHooks().setCurrentFocusedElement(getParent());
                    return true;
                }
                return super.keyDown(keyCode);
            }

            @Override
            public void deactivate() {
                super.deactivate();
                KeyFrame keyFrame = timeline.getCurrentSelectedKeyFrame();
                if (getText().length() > 0 && getText().length() < 10 && keyFrame != null) {
                    KeyFrame stateBeforeOperation = keyFrame.makeCopy();
                    keyFrame.rotation = Float.parseFloat(getText());
                    KeyFrame stateAfterOperation = keyFrame.makeCopy();
                    if (keyFrame.rotation != stateBeforeOperation.rotation) {
                        Operation operation = getOperation(stateBeforeOperation, stateAfterOperation, keyFrame);
                        operation.setName(LocalizedStrings.getStrings(ID).get(18));
                        historyPanel.addOperation(operation);
                        refreshKeyFrameProperty();
                    }
                }
            }
        };
        rotation.setId("rotation");
        rotation.setCharFilter("[0-9.\\-]");

        GCheckBox visible = new GCheckBox(getWidth() * 0.3F, lVisible.getY(false) - getHeight() * 0.015F, 16, 16, bannerFont) {
            @Override
            public void onClick() {
                KeyFrame keyFrame = timeline.getCurrentSelectedKeyFrame();
                if (keyFrame != null) {
                    KeyFrame stateBeforeOperation = keyFrame.makeCopy();
                    keyFrame.visible = getState() == 1;
                    KeyFrame stateAfterOperation = keyFrame.makeCopy();
                    if (keyFrame.visible != stateBeforeOperation.visible) {
                        Operation operation = getOperation(stateBeforeOperation, stateAfterOperation, keyFrame);
                        operation.setName(LocalizedStrings.getStrings(ID).get(19));
                        historyPanel.addOperation(operation);
                        refreshKeyFrameProperty();
                    }
                }
            }
        };
        visible.setId("visible");
        visible.setText("");

        GTextField tintR = new GTextField(getWidth() * 0.25F, lTint.getY(false) - getHeight() * 0.035F, getWidth() * 0.15F, lTint.getHeight(), bannerFont) {
            @Override
            public boolean keyDown(int keyCode) {
                if (keyCode == Input.Keys.ENTER && FormManager.getInstance().getEventHooks().getCurrentFocusedElement() == this) {
                    FormManager.getInstance().getEventHooks().setCurrentFocusedElement(getParent());
                    return true;
                }
                return super.keyDown(keyCode);
            }

            @Override
            public void deactivate() {
                super.deactivate();
                KeyFrame keyFrame = timeline.getCurrentSelectedKeyFrame();
                if (getText().length() > 0 && getText().length() < 10 && keyFrame != null && (int) Double.parseDouble(getText()) < 256) {
                    KeyFrame stateBeforeOperation = keyFrame.makeCopy();
                    keyFrame.tint.r = Float.parseFloat(getText()) / 255.0F;
                    KeyFrame stateAfterOperation = keyFrame.makeCopy();
                    if (keyFrame.tint.r != stateBeforeOperation.tint.r) {
                        Operation operation = getOperation(stateBeforeOperation, stateAfterOperation, keyFrame);
                        operation.setName(LocalizedStrings.getStrings(ID).get(20));
                        historyPanel.addOperation(operation);
                        refreshKeyFrameProperty();
                    }
                }
            }
        };
        tintR.setId("tintR");
        tintR.setCharFilter("[0-9]");
        GTextField tintG = new GTextField(getWidth() * 0.4F + 3, lTint.getY(false) - getHeight() * 0.035F, getWidth() * 0.15F, lTint.getHeight(), bannerFont) {
            @Override
            public boolean keyDown(int keyCode) {
                if (keyCode == Input.Keys.ENTER && FormManager.getInstance().getEventHooks().getCurrentFocusedElement() == this) {
                    FormManager.getInstance().getEventHooks().setCurrentFocusedElement(getParent());
                    return true;
                }
                return super.keyDown(keyCode);
            }

            @Override
            public void deactivate() {
                super.deactivate();
                KeyFrame keyFrame = timeline.getCurrentSelectedKeyFrame();
                if (getText().length() > 0 && getText().length() < 10 && keyFrame != null && (int) Double.parseDouble(getText()) < 256) {
                    KeyFrame stateBeforeOperation = keyFrame.makeCopy();
                    keyFrame.tint.g = Float.parseFloat(getText()) / 255.0F;
                    KeyFrame stateAfterOperation = keyFrame.makeCopy();
                    if (keyFrame.tint.g != stateBeforeOperation.tint.g) {
                        Operation operation = getOperation(stateBeforeOperation, stateAfterOperation, keyFrame);
                        operation.setName(LocalizedStrings.getStrings(ID).get(20));
                        historyPanel.addOperation(operation);
                        refreshKeyFrameProperty();
                    }
                }
            }
        };
        tintG.setId("tintG");
        tintG.setCharFilter("[0-9]");
        GTextField tintB = new GTextField(getWidth() * 0.55F + 6, lTint.getY(false) - getHeight() * 0.035F, getWidth() * 0.15F, lTint.getHeight(), bannerFont) {
            @Override
            public boolean keyDown(int keyCode) {
                if (keyCode == Input.Keys.ENTER && FormManager.getInstance().getEventHooks().getCurrentFocusedElement() == this) {
                    FormManager.getInstance().getEventHooks().setCurrentFocusedElement(getParent());
                    return true;
                }
                return super.keyDown(keyCode);
            }

            @Override
            public void deactivate() {
                super.deactivate();
                KeyFrame keyFrame = timeline.getCurrentSelectedKeyFrame();
                if (getText().length() > 0 && getText().length() < 10 && keyFrame != null && (int) Double.parseDouble(getText()) < 256) {
                    KeyFrame stateBeforeOperation = keyFrame.makeCopy();
                    keyFrame.tint.b = Float.parseFloat(getText()) / 255.0F;
                    KeyFrame stateAfterOperation = keyFrame.makeCopy();
                    if (keyFrame.tint.b != stateBeforeOperation.tint.b) {
                        Operation operation = getOperation(stateBeforeOperation, stateAfterOperation, keyFrame);
                        operation.setName(LocalizedStrings.getStrings(ID).get(20));
                        historyPanel.addOperation(operation);
                        refreshKeyFrameProperty();
                    }
                }
            }
        };
        tintB.setId("tintB");
        tintB.setCharFilter("[0-9]");
        GTextField tintA = new GTextField(getWidth() * 0.7F + 9, lTint.getY(false) - getHeight() * 0.035F, getWidth() * 0.15F, lTint.getHeight(), bannerFont) {
            @Override
            public boolean keyDown(int keyCode) {
                if (keyCode == Input.Keys.ENTER && FormManager.getInstance().getEventHooks().getCurrentFocusedElement() == this) {
                    FormManager.getInstance().getEventHooks().setCurrentFocusedElement(getParent());
                    return true;
                }
                return super.keyDown(keyCode);
            }

            @Override
            public void deactivate() {
                super.deactivate();
                KeyFrame keyFrame = timeline.getCurrentSelectedKeyFrame();
                if (getText().length() > 0 && getText().length() < 10 && keyFrame != null && (int) Double.parseDouble(getText()) < 256) {
                    KeyFrame stateBeforeOperation = keyFrame.makeCopy();
                    keyFrame.tint.a = Float.parseFloat(getText()) / 255.0F;
                    KeyFrame stateAfterOperation = keyFrame.makeCopy();
                    if (keyFrame.tint.a != stateBeforeOperation.tint.a) {
                        Operation operation = getOperation(stateBeforeOperation, stateAfterOperation, keyFrame);
                        operation.setName(LocalizedStrings.getStrings(ID).get(20));
                        historyPanel.addOperation(operation);
                        refreshKeyFrameProperty();
                    }
                }
            }
        };
        tintA.setId("tintA");
        tintA.setCharFilter("[0-9]");

        GTextField offsetR = new GTextField(getWidth() * 0.45F, lColorOffset.getY(false) - getHeight() * 0.035F, getWidth() * 0.15F, lColorOffset.getHeight(), bannerFont) {
            @Override
            public boolean keyDown(int keyCode) {
                if (keyCode == Input.Keys.ENTER && FormManager.getInstance().getEventHooks().getCurrentFocusedElement() == this) {
                    FormManager.getInstance().getEventHooks().setCurrentFocusedElement(getParent());
                    return true;
                }
                return super.keyDown(keyCode);
            }

            @Override
            public void deactivate() {
                super.deactivate();
                KeyFrame keyFrame = timeline.getCurrentSelectedKeyFrame();
                if (getText().length() > 0 && getText().length() < 10 && keyFrame != null && (int) Double.parseDouble(getText()) < 256) {
                    KeyFrame stateBeforeOperation = keyFrame.makeCopy();
                    keyFrame.colorOffset.r = Float.parseFloat(getText()) / 255.0F;
                    KeyFrame stateAfterOperation = keyFrame.makeCopy();
                    if (keyFrame.colorOffset.r != stateBeforeOperation.colorOffset.r) {
                        Operation operation = getOperation(stateBeforeOperation, stateAfterOperation, keyFrame);
                        operation.setName(LocalizedStrings.getStrings(ID).get(21));
                        historyPanel.addOperation(operation);
                        refreshKeyFrameProperty();
                    }
                }
            }
        };
        offsetR.setId("offsetR");
        offsetR.setCharFilter("[0-9]");
        GTextField offsetG = new GTextField(getWidth() * 0.6F + 3, lColorOffset.getY(false) - getHeight() * 0.035F, getWidth() * 0.15F, lColorOffset.getHeight(), bannerFont) {
            @Override
            public boolean keyDown(int keyCode) {
                if (keyCode == Input.Keys.ENTER && FormManager.getInstance().getEventHooks().getCurrentFocusedElement() == this) {
                    FormManager.getInstance().getEventHooks().setCurrentFocusedElement(getParent());
                    return true;
                }
                return super.keyDown(keyCode);
            }

            @Override
            public void deactivate() {
                super.deactivate();
                KeyFrame keyFrame = timeline.getCurrentSelectedKeyFrame();
                if (getText().length() > 0 && getText().length() < 10 && keyFrame != null && (int) Double.parseDouble(getText()) < 256) {
                    KeyFrame stateBeforeOperation = keyFrame.makeCopy();
                    keyFrame.colorOffset.g = Float.parseFloat(getText()) / 255.0F;
                    KeyFrame stateAfterOperation = keyFrame.makeCopy();
                    if (keyFrame.colorOffset.g != stateBeforeOperation.colorOffset.g) {
                        Operation operation = getOperation(stateBeforeOperation, stateAfterOperation, keyFrame);
                        operation.setName(LocalizedStrings.getStrings(ID).get(21));
                        historyPanel.addOperation(operation);
                        refreshKeyFrameProperty();
                    }
                }
            }
        };
        offsetG.setId("offsetG");
        offsetG.setCharFilter("[0-9]");
        GTextField offsetB = new GTextField(getWidth() * 0.75F + 6, lColorOffset.getY(false) - getHeight() * 0.035F, getWidth() * 0.15F, lColorOffset.getHeight(), bannerFont) {
            @Override
            public boolean keyDown(int keyCode) {
                if (keyCode == Input.Keys.ENTER && FormManager.getInstance().getEventHooks().getCurrentFocusedElement() == this) {
                    FormManager.getInstance().getEventHooks().setCurrentFocusedElement(getParent());
                    return true;
                }
                return super.keyDown(keyCode);
            }

            @Override
            public void deactivate() {
                super.deactivate();
                KeyFrame keyFrame = timeline.getCurrentSelectedKeyFrame();
                if (getText().length() > 0 && getText().length() < 10 && keyFrame != null && (int) Double.parseDouble(getText()) < 256) {
                    KeyFrame stateBeforeOperation = keyFrame.makeCopy();
                    keyFrame.colorOffset.b = Float.parseFloat(getText()) / 255.0F;
                    KeyFrame stateAfterOperation = keyFrame.makeCopy();
                    if (keyFrame.colorOffset.b != stateBeforeOperation.colorOffset.b) {
                        Operation operation = getOperation(stateBeforeOperation, stateAfterOperation, keyFrame);
                        operation.setName(LocalizedStrings.getStrings(ID).get(21));
                        historyPanel.addOperation(operation);
                        refreshKeyFrameProperty();
                    }
                }
            }
        };
        offsetB.setId("offsetB");
        offsetB.setCharFilter("[0-9]");

        GCheckBox inter = new GCheckBox(getWidth() * 0.45F, lInter.getY(false) - getHeight() * 0.015F, 16, 16, bannerFont) {
            @Override
            public void onClick() {
                KeyFrame keyFrame = timeline.getCurrentSelectedKeyFrame();
                if (keyFrame != null) {
                    KeyFrame stateBeforeOperation = keyFrame.makeCopy();
                    keyFrame.interpolated = getState() == 1;
                    KeyFrame stateAfterOperation = keyFrame.makeCopy();
                    if (keyFrame.interpolated != stateBeforeOperation.interpolated) {
                        Operation operation = getOperation(stateBeforeOperation, stateAfterOperation, keyFrame);
                        operation.setName(LocalizedStrings.getStrings(ID).get(22));
                        historyPanel.addOperation(operation);
                        refreshKeyFrameProperty();
                    }
                }
            }
        };
        inter.setId("inter");
        inter.setText("");
        GButton areaName = new GButton(getWidth() * 0.53F, lAreaName.getY(false) - getHeight() * 0.02F, getWidth() * 0.47F, lAreaName.getHeight() - getHeight() * 0.02F, bannerFont) {
            @Override
            public void onClick() {
                Track track = timeline.getCurrentSelectedTrack();
                if (track != null) {
                    SpriteSheet spriteSheet = Project.currentProject.getSpriteSheet(track.getSpriteSheetId());
                    if (spriteSheet != null && spriteSheet.hasAtlasData()) {
                        KeyFrame keyFrame = timeline.getCurrentSelectedKeyFrame();
                        KeyFrame stateBeforeChange = keyFrame == null ? null : keyFrame.makeCopy();
                        if (keyFrame != null) {
                            List<String> options = new ArrayList<>(spriteSheet.getRegions().keySet());
                            options.sort(String::compareTo);
                            int index = -1;
                            int t = 0;
                            for (String name : options) {
                                TextureAtlas.TextureAtlasData.Region region = spriteSheet.getRegion(name);
                                if (region.left == keyFrame.xCrop && region.top == keyFrame.yCrop && keyFrame.width == region.width && keyFrame.height == region.height) {
                                    index = t;
                                    break;
                                }
                                t++;
                            }
                            OptionWindow optionWindow = new OptionWindow(LocalizedStrings.getStrings(ID).get(24), options, bannerFont, Math.max(index, 0)) {
                                @Override
                                public void render(SpriteBatch sb) {
                                    super.render(sb);
                                    GRadioButton selectedOption = null;
                                    for (GRadioButton radioButton : buttonGroup) {
                                        if (radioButton.getState() == 1) {
                                            selectedOption = radioButton;
                                            break;
                                        }
                                    }
                                    if (selectedOption != null) {
                                        TextureAtlas.TextureAtlasData.Region region = spriteSheet.getRegion(selectedOption.getText());

                                        TextureRegion textureRegion = new TextureRegion(spriteSheet.getSprite(), region.left, region.top, region.rotate ? region.height : region.width, region.rotate ? region.width : region.height);
                                        sb.setColor(1, 1, 1, 0.6F);
                                        sb.draw(textureRegion, getX(true) + (getWidth() - region.width) / 2.0F, getY(true) + (getHeight() - region.height) / 2.0F,
                                                region.width / 2.0F, region.height / 2.0F, textureRegion.getRegionWidth(), textureRegion.getRegionHeight(), 1.0F, 1.0F, region.rotate ? 90.0F : 0.0F);
                                        sb.flush();
                                    }
                                }
                            };
                            optionWindow.setY(Gdx.graphics.getHeight() * 0.2F);
                            optionWindow.setConfirmCallback(i -> {
                                TextureAtlas.TextureAtlasData.Region region = spriteSheet.getRegion(options.get(i));
                                if (region != null) {
                                    keyFrame.xCrop = region.left;
                                    keyFrame.yCrop = region.top;
                                    keyFrame.width = region.width;
                                    keyFrame.height = region.height;
                                    keyFrame.xPivot = region.width / 2.0F;
                                    keyFrame.yPivot = region.height / 2.0F;
                                    if (region.rotate) {
                                        int tmp = keyFrame.width;
                                        keyFrame.width = keyFrame.height;
                                        keyFrame.height = tmp;
                                        keyFrame.rotation = -90;
                                    }
                                    String prevName = timeline.getCurrentSelectedTrack().getName();
                                    String nextName = Preferences.getPreferences().renameTrackAfterChangeRegion() ? options.get(i) : prevName;
                                    TrackPane trackPane = (TrackPane) FormManager.getInstance().getContainerById(TrackPane.ID);
                                    timeline.getCurrentSelectedTrack().setName(nextName);
                                    for (GList.ListCellRenderer<TrackInfoItem> cellRenderer : trackPane.getTrackInfoList().getElements()) {
                                        TrackInfoItem trackInfoItem = cellRenderer.getElements().get(0);
                                        if (trackInfoItem.getTrack() == timeline.getCurrentSelectedTrack()) {
                                            trackInfoItem.getTrackName().setText(nextName);
                                            break;
                                        }
                                    }
                                    refreshKeyFrameProperty();
                                    Operation operation = new Operation() {
                                        @Override
                                        public void undo() {
                                            keyFrame.xCrop = stateBeforeChange.xCrop;
                                            keyFrame.yCrop = stateBeforeChange.yCrop;
                                            keyFrame.width = stateBeforeChange.width;
                                            keyFrame.height = stateBeforeChange.height;
                                            keyFrame.xPivot = stateBeforeChange.xPivot;
                                            keyFrame.yPivot = stateBeforeChange.yPivot;
                                            timeline.getCurrentSelectedTrack().setName(prevName);
                                            for (GList.ListCellRenderer<TrackInfoItem> cellRenderer : trackPane.getTrackInfoList().getElements()) {
                                                TrackInfoItem trackInfoItem = cellRenderer.getElements().get(0);
                                                if (trackInfoItem.getTrack() == timeline.getCurrentSelectedTrack()) {
                                                    trackInfoItem.getTrackName().setText(prevName);
                                                    break;
                                                }
                                            }
                                            refreshKeyFrameProperty();
                                        }

                                        @Override
                                        public void redo() {
                                            keyFrame.xCrop = region.left;
                                            keyFrame.yCrop = region.top;
                                            keyFrame.width = region.width;
                                            keyFrame.height = region.height;
                                            keyFrame.xPivot = region.width / 2.0F;
                                            keyFrame.yPivot = region.height / 2.0F;
                                            if (region.rotate) {
                                                int tmp = keyFrame.width;
                                                keyFrame.width = keyFrame.height;
                                                keyFrame.height = tmp;
                                                keyFrame.rotation = -90;
                                            }
                                            timeline.getCurrentSelectedTrack().setName(nextName);
                                            for (GList.ListCellRenderer<TrackInfoItem> cellRenderer : trackPane.getTrackInfoList().getElements()) {
                                                TrackInfoItem trackInfoItem = cellRenderer.getElements().get(0);
                                                if (trackInfoItem.getTrack() == timeline.getCurrentSelectedTrack()) {
                                                    trackInfoItem.getTrackName().setText(nextName);
                                                    break;
                                                }
                                            }
                                            refreshKeyFrameProperty();
                                        }
                                    };
                                    operation.setName(LocalizedStrings.getStrings(ID).get(25));
                                    historyPanel.addOperation(operation);
                                }
                            });
                        }
                    }
                }
            }
        };
        areaName.setId("areaName");
        areaName.setText(strings.get(24) + "...");
        areaName.setBackground(new Color(0, 47.0F / 255.0F, 147.0F / 255.0F, 1.0F));
        areaName.setBorderWidth(2);
        areaName.setBorder(Color.LIGHT_GRAY.cpy());
        areaName.setVisible(false);

        addElement(x);
        addElement(y);
        addElement(originX);
        addElement(originY);
        addElement(srcX);
        addElement(srcY);
        addElement(width);
        addElement(height);
        addElement(scaleX);
        addElement(scaleY);
        addElement(delay);
        addElement(rotation);
        addElement(visible);
        addElement(tintR);
        addElement(tintG);
        addElement(tintB);
        addElement(tintA);
        addElement(offsetR);
        addElement(offsetG);
        addElement(offsetB);
        addElement(inter);
        addElement(areaName);
    }

    public void refreshKeyFrameProperty() {
        Timeline timeline = (Timeline) FormManager.getInstance().getContainerById(Timeline.ID);
        KeyFrame keyFrame = timeline.getCurrentSelectedKeyFrame();
        if (keyFrame != null) {
            GTextField x = (GTextField) getElementById("x");
            GTextField y = (GTextField) getElementById("y");
            GTextField originX = (GTextField) getElementById("originX");
            GTextField originY = (GTextField) getElementById("originY");
            GTextField srcX = (GTextField) getElementById("srcX");
            GTextField srcY = (GTextField) getElementById("srcY");
            GTextField width = (GTextField) getElementById("width");
            GTextField height = (GTextField) getElementById("height");
            GTextField scaleX = (GTextField) getElementById("scaleX");
            GTextField scaleY = (GTextField) getElementById("scaleY");
            GTextField delay = (GTextField) getElementById("delay");
            GTextField rotation = (GTextField) getElementById("rotation");
            GCheckBox visible = (GCheckBox) getElementById("visible");
            GTextField tintR = (GTextField) getElementById("tintR");
            GTextField tintG = (GTextField) getElementById("tintG");
            GTextField tintB = (GTextField) getElementById("tintB");
            GTextField tintA = (GTextField) getElementById("tintA");
            GTextField offsetR = (GTextField) getElementById("offsetR");
            GTextField offsetG = (GTextField) getElementById("offsetG");
            GTextField offsetB = (GTextField) getElementById("offsetB");
            GCheckBox inter = (GCheckBox) getElementById("inter");
            GLabel lAreaName = (GLabel) getElementById("lAreaName");
            GButton areaName = (GButton) getElementById("areaName");
            x.setText(Float.toString(keyFrame.xPosition));
            y.setText(Float.toString(keyFrame.yPosition));
            originX.setText(Float.toString(keyFrame.xPivot));
            originY.setText(Float.toString(keyFrame.yPivot));
            srcX.setText(Integer.toString(keyFrame.xCrop));
            srcY.setText(Integer.toString(keyFrame.yCrop));
            width.setText(Integer.toString(keyFrame.width));
            height.setText(Integer.toString(keyFrame.height));
            scaleX.setText(Float.toString(keyFrame.xScale));
            scaleY.setText(Float.toString(keyFrame.yScale));
            delay.setText(Integer.toString(keyFrame.delay));
            rotation.setText(Float.toString(keyFrame.rotation));
            visible.setState(keyFrame.visible ? 1 : 0);
            tintR.setText(Integer.toString((int) (keyFrame.tint.r * 255)));
            tintG.setText(Integer.toString((int) (keyFrame.tint.g * 255)));
            tintB.setText(Integer.toString((int) (keyFrame.tint.b * 255)));
            tintA.setText(Integer.toString((int) (keyFrame.tint.a * 255)));
            offsetR.setText(Integer.toString((int) (keyFrame.colorOffset.r * 255)));
            offsetG.setText(Integer.toString((int) (keyFrame.colorOffset.g * 255)));
            offsetB.setText(Integer.toString((int) (keyFrame.colorOffset.b * 255)));
            inter.setState(keyFrame.interpolated ? 1 : 0);
            Track track = timeline.getCurrentSelectedTrack();
            if (track != null) {
                SpriteSheet spriteSheet = Project.currentProject.getSpriteSheet(track.getSpriteSheetId());
                if (spriteSheet != null) {
                    if (spriteSheet.hasAtlasData()) {
                        lAreaName.setVisible(true);
                        areaName.setVisible(true);
                    } else {
                        spriteSheet.loadAtlasData();
                        if (spriteSheet.hasAtlasData()) {
                            lAreaName.setVisible(true);
                            areaName.setVisible(true);
                        } else {
                            lAreaName.setVisible(false);
                            areaName.setVisible(false);
                        }
                    }
                } else {
                    lAreaName.setVisible(false);
                    areaName.setVisible(false);
                }
            } else {
                lAreaName.setVisible(false);
                areaName.setVisible(false);
            }
        }
    }

    private Operation getOperation(KeyFrame stateBeforeOperation, KeyFrame stateAfterOperation, KeyFrame target) {
        return new Operation() {
            @Override
            public void undo() {
                if (stateBeforeOperation != null && target != null) {
                    target.xPosition = stateBeforeOperation.xPosition;
                    target.yPosition = stateBeforeOperation.yPosition;
                    target.xPivot = stateBeforeOperation.xPivot;
                    target.yPivot = stateBeforeOperation.yPivot;
                    target.xCrop = stateBeforeOperation.xCrop;
                    target.yCrop = stateBeforeOperation.yCrop;
                    target.width = stateBeforeOperation.width;
                    target.height = stateBeforeOperation.height;
                    target.xScale = stateBeforeOperation.xScale;
                    target.yScale = stateBeforeOperation.yScale;
                    target.delay = stateBeforeOperation.delay;
                    target.visible = stateBeforeOperation.visible;
                    target.tint = stateBeforeOperation.tint;
                    target.colorOffset = stateBeforeOperation.colorOffset;
                    target.rotation = stateBeforeOperation.rotation;
                    target.interpolated = stateBeforeOperation.interpolated;
                    refreshKeyFrameProperty();
                }
            }

            @Override
            public void redo() {
                if (stateAfterOperation != null && target != null) {
                    target.xPosition = stateAfterOperation.xPosition;
                    target.yPosition = stateAfterOperation.yPosition;
                    target.xPivot = stateAfterOperation.xPivot;
                    target.yPivot = stateAfterOperation.yPivot;
                    target.xCrop = stateAfterOperation.xCrop;
                    target.yCrop = stateAfterOperation.yCrop;
                    target.width = stateAfterOperation.width;
                    target.height = stateAfterOperation.height;
                    target.xScale = stateAfterOperation.xScale;
                    target.yScale = stateAfterOperation.yScale;
                    target.delay = stateAfterOperation.delay;
                    target.visible = stateAfterOperation.visible;
                    target.tint = stateAfterOperation.tint;
                    target.colorOffset = stateAfterOperation.colorOffset;
                    target.rotation = stateAfterOperation.rotation;
                    target.interpolated = stateAfterOperation.interpolated;
                    refreshKeyFrameProperty();
                }
            }
        };
    }

    @Override
    public void onReloadStrings() {
        List<String> strings = LocalizedStrings.getStrings(ID);
        setTitle(strings.get(0));
        GLabel lPosition = (GLabel) getElementById("lPosition");
        lPosition.setText(strings.get(1));
        GLabel lOrigin = (GLabel) getElementById("lOrigin");
        lOrigin.setText(strings.get(2));
        GLabel lSrc = (GLabel) getElementById("lSrc");
        lSrc.setText(strings.get(3));
        GLabel lSize = (GLabel) getElementById("lSize");
        lSize.setText(strings.get(4));
        GLabel lScale = (GLabel) getElementById("lScale");
        lScale.setText(strings.get(5));
        GLabel lDelay = (GLabel) getElementById("lDelay");
        lDelay.setText(strings.get(6));
        GLabel lRotation = (GLabel) getElementById("lRotation");
        lRotation.setText(strings.get(7));
        GLabel lVisible = (GLabel) getElementById("lVisible");
        lVisible.setText(strings.get(8));
        GLabel lTint = (GLabel) getElementById("lTint");
        lTint.setText(strings.get(9));
        GLabel lColorOffset = (GLabel) getElementById("lColorOffset");
        lColorOffset.setText(strings.get(10));
        GLabel lInter = (GLabel) getElementById("lInter");
        lInter.setText(strings.get(11));
        GLabel lAreaName = (GLabel) getElementById("lAreaName");
        lAreaName.setText(strings.get(23));
        GButton areaName = (GButton) getElementById("areaName");
        areaName.setText(strings.get(24) + "...");
    }
}
